package com.sinszm.mdb.pagebar;


import com.sinszm.common.exception.ApiException;
import com.sinszm.mdb.pagebar.annotation.Rv;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.nutz.json.Json;
import org.nutz.json.JsonFormat;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.format.ResolverStyle;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 分页请求参数
 *
 * @author chenjianbo
 */
@ApiModel(value = "分页请求")
public class WebPageRequest {

    /**
     * 当前页码
     */
    @ApiModelProperty(value = "当前页码", dataType = "Integer", example = "1")
    private int currentNum = 1;

    /**
     * 每页显示数量
     */
    @ApiModelProperty(value = "每页显示数量", dataType = "Integer", example = "10")
    private int pageSize = 10;

    /**
     * 字段名称
     */
    @ApiModelProperty(value = "字段名称", dataType = "String")
    private String field;

    /**
     * 排序方向
     */
    @ApiModelProperty(value = "排序方向", dataType = "String", example = "DESC")
    private String sorted;

    public WebPageRequest() {
    }

    public WebPageRequest(int currentNum, int pageSize) {
        this.currentNum = currentNum;
        this.pageSize = pageSize;
    }

    public WebPageRequest(int currentNum, int pageSize, String field, String sorted) {
        this.currentNum = currentNum;
        this.pageSize = pageSize;
        this.field = field;
        this.sorted = sorted;
    }

    /**
     * 返回包含子类实现的所有参数Map集
     *
     * @return 参数集
     */
    public Map<String, Object> parameter() {
        return new HashMap<>(Json.fromJsonAsMap(Object.class, Json.toJson(this, JsonFormat.full())));
    }

    /**
     * 检查所有参数合法性
     */
    public void checkAllParameters() {
        Object params = this;
        Class<?> clazz = params.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            Rv rv = field.getAnnotation(Rv.class);
            if (rv == null || !rv.required()) {
                continue;
            }
            field.setAccessible(true);
            try {
                Object object = field.get(params);
                validate(object, rv, field);
            } catch (IllegalAccessException e) {
                e.printStackTrace(System.err);
            }
        }
    }

    /**
     * 验证处理逻辑
     * @param object    字段对象
     * @param rv        验证规则
     */
    private void validate(Object object, Rv rv, Field field) {
        assert rv != null;
        //如果数据规则可以为空，则后续规则不验证
        boolean nullable = rv.nullable();
        if (nullable) {
            return;
        }
        if (object == null) {
            throw new ApiException("FIELD-NULL-ERROR", field.getName() + "字段不能为空");
        }
        //主要对字符串类型的各种数据要求验证
        String className = object.getClass().getSimpleName();
        if (String.class.getSimpleName().equals(className)) {
            String value = String.valueOf(object);
            List<String> types = Arrays.stream(rv.types())
                    .map(RvType::name)
                    .collect(Collectors.toList());
            //验证长度
            if (types.contains(RvType.LENGTH.name())) {
                if (value.length() < rv.minLength()) {
                    throw new ApiException("FIELD-LENGTH-ERROR", field.getName() + "字段最小长度为" + rv.minLength());
                }
                if (value.length() > rv.maxLength()) {
                    throw new ApiException("FIELD-LENGTH-ERROR", field.getName() + "字段最大长度为" + rv.maxLength());
                }
            }
            //验证正则表达式
            if (types.contains(RvType.REGEX.name())) {
                boolean state = StringUtils.hasText(rv.regex()) && Pattern.matches(rv.regex(), value);
                if (!state) {
                    throw new ApiException("FIELD-REGEX-ERROR", field.getName() + "字段违反字符规则");
                }
            }
            //验证时间字符串格式
            if (types.contains(RvType.TIME.name())
                    && StringUtils.hasText(rv.dateFormat())) {
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
                        rv.dateFormat().replace("y", "u")
                ).withResolverStyle(ResolverStyle.STRICT);
                try {
                    LocalDate.parse(value, formatter);
                } catch (DateTimeParseException | NullPointerException e) {
                    throw new ApiException("FIELD-TIME-ERROR", field.getName() + "字段违反日期规则格式");
                }
            }
        }
    }

    /**
     * 获取当前页码
     * @return 页码
     */
    public int getCurrentNum() {
        return currentNum = Math.max(currentNum, 1);
    }

    /**
     * 获取每页显示数量
     * @return 每页数量
     */
    public int getPageSize() {
        return pageSize = pageSize < 1 ? 10: pageSize;
    }

    /**
     * 排序字段名
     * @return 字段名
     */
    public String getField() {
        return this.field;
    }

    /**
     * 排序字段对应的方向
     * @return 排序方向
     */
    public String getSorted() {
        return this.sorted;
    }

    /**###########################################################*/

    public void setCurrentNum(int currentNum) {
        this.currentNum = currentNum;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public void setField(String field) {
        this.field = field;
    }

    public void setSorted(String sorted) {
        this.sorted = sorted;
    }

}